﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics.Contracts;
using System.Linq;
using System.ServiceModel;
using System.Web;
using WmsService.Cache;
using WmsService.Exceptions;

namespace WmsService.Security
{
    public class Authentication : IAuthentication
    {
        #region Implementation of IAuthentication

        public string Login(string userID, string password)
        {
            try
            {
                Contract.Requires(!String.IsNullOrEmpty(userID) && !String.IsNullOrEmpty(password),
                    "用户和密码不能为空！");

                SystemUser user = GetSystemUser(userID);
                if (user == null)
                {
                    return "无此用户：" + userID;
                }
                if (user.PASSWORD != password)
                {
                    return "密码错误！" ;
                }
                if (user.ISVALID != Constant.IsValidTrue)
                {
                    return "该账户已经锁定，请联系管理员：" + userID;
                }
                string sessionID = Guid.NewGuid().ToString("N");  //HttpContext.Current.Session.SessionID;
                string token = "token:" +Cryptographer.EncryptDES(sessionID,Cryptographer.GetEncryptKey());

                var ctx = Factory.ContextFactory.Create();
      
                UserToken userToken = UserToken.CreateUserToken(sessionID, userID, DateTime.Now);
                userToken.UPDATETIME = DateTime.Now;
                userToken.USERNAME = user.USERNAME;
                //该字段记录此sessionid从数据库中刷过多少次，每一次当cache中不存在的时候就刷
                userToken.ExtNumeric1 = 1;
                ctx.AddToUserToken(userToken);
                ctx.SaveChanges();
                DataCacheManager.SetSessionKey(sessionID);
                DataCacheManager.SetUserID(sessionID,userToken.USERID);
                DataCacheManager.SetUserName(sessionID,userToken.USERNAME);
             
                return token;
            }
            catch (Exception ex)
            {
                return Exceptions.ExceptionHandler.GetDetialException(ex);
            }
        }

// ReSharper disable MemberCanBeMadeStatic.Local
        private SystemUser GetSystemUser(string userID)
// ReSharper restore MemberCanBeMadeStatic.Local
        {
            using (var ctx = Factory.ContextFactory.Create())
            {
                var q = from c in ctx.SystemUser
                        where c.USERID == userID
                        select c;
                List<SystemUser> list = q.ToList();
                if (list.Count == 0)
                    return null;
                ctx.Detach(list[0]);
                return list[0];
            }
        }

        public void ValidateToken(string token)
        {
            string sessionID = String.Empty;
            try
            {
                sessionID = Cryptographer.DecryptDES(token, Cryptographer.GetEncryptKey());
            }
            catch (Exception )
            {
                 Exceptions.ExceptionHandler.ThrowException("非法token！");
            }

            //查询缓存，如果不存在，则查询数据库
            if(!DataCacheManager.ContainSessionKey(sessionID))
            {
                //查询数据库，如果不存在，报错，如果存在，则重新塞入缓存，同时更新updatetime
                var ctx = Factory.ContextFactory.Create();
                var query = from u in ctx.UserToken
                            where u.SessionID == sessionID
                            select u;
                if (query.ToList().Count > 0)
                {
                    UserToken tmp = query.ToList()[0];

                    if(DateTime.Now - tmp.CREATETIME > new TimeSpan(7,0,0,0) )
                    {
                        Exceptions.ExceptionHandler.ThrowException("登录token已经超过7天，为了安全，请重新登录！");
                    }
                    ctx.Detach(tmp);
                    tmp.UPDATETIME = DateTime.Now;
                    tmp.ExtNumeric1 = tmp.ExtNumeric1 + 1;
                    ctx.AddToUserToken(tmp);
                    ctx.ObjectStateManager.ChangeObjectState(tmp, EntityState.Modified);
                    ctx.SaveChanges();
                    DataCacheManager.SetSessionKey(sessionID);
                    DataCacheManager.SetUserID(sessionID,tmp.USERID);
                    DataCacheManager.SetUserName(sessionID,tmp.USERNAME);
                }
                else
                {
                     Exceptions.ExceptionHandler.ThrowException("非法token，或者token已经过期，请重新登录！");
                }
            }
        }

        public string GetCurrentUserID(string token)
        {
            string sessionID = String.Empty;
            try
            {
                sessionID = Cryptographer.DecryptDES(token, Cryptographer.GetEncryptKey());
            }
            catch (Exception)
            {
                 Exceptions.ExceptionHandler.ThrowException("非法token！");
            }
            string userID= DataCacheManager.GetUserID(sessionID);
            if(string.IsNullOrEmpty(userID))
            {
                ValidateToken(token);
                return GetCurrentUserID(token);
            }
            return userID;
        }

        public string GetCurrentUserName(string token)
        {
            string sessionID = String.Empty;
            try
            {
                sessionID = Cryptographer.DecryptDES(token, Cryptographer.GetEncryptKey());
            }
            catch (Exception)
            {
                 Exceptions.ExceptionHandler.ThrowException("非法token！");
            }
            string userName = DataCacheManager.GetUserName(sessionID);
            if (string.IsNullOrEmpty(userName))
            {
                ValidateToken(token);
                return GetCurrentUserName(token);
            }
            return userName;
        }

        public void ValidateToken()
        {
            ValidateToken(GetContextToken());
        }

        public string GetContextToken()
        {
            var token = OperationContext.Current.IncomingMessageHeaders.GetHeader<String>("token", "ns");
            return token;
        }

        public string GetCurrentUserID()
        {
            return GetCurrentUserID(GetContextToken());
        }

        public string GetCurrentUserName()
        {
            return GetCurrentUserName(GetContextToken());
        }
        #endregion
    }
}